# -*- coding: utf-8 -*-
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import mean_squared_error
from keras.models import Sequential
from keras.layers import LSTM, Dense
import warnings
import chardet
import matplotlib
warnings.filterwarnings("ignore")

# ==================== 字体设置 ====================
# 方法1：使用系统常见中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'WenQuanYi Zen Hei', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题

# 方法2：动态检测可用字体（更健壮）
try:
    plt.rcParams['font.sans-serif'] = ['SimHei']  # 首选字体
    plt.rcParams['axes.unicode_minus'] = False
    # 测试字体是否可用
    plt.plot([1, 2], [1, 2])
    plt.title('字体测试')
    plt.close()
except:
    # 如果首选字体不可用，尝试其他字体
    available_fonts = ['Microsoft YaHei', 'Arial Unicode MS', 'sans-serif']
    for font in available_fonts:
        try:
            plt.rcParams['font.sans-serif'] = [font]
            plt.plot([1, 2], [1, 2])
            plt.title('字体测试')
            plt.close()
            print(f"使用替代字体: {font}")
            break
        except:
            continue

# ==================== 数据加载 ====================
def detect_encoding(file_path):
    with open(file_path, 'rb') as f:
        return chardet.detect(f.read(10000))['encoding']

file_path = "D:/MathD/中国平安2318历史数据.csv"
try:
    encoding = detect_encoding(file_path)
    data = pd.read_csv(file_path, encoding=encoding)
except Exception as e:
    print(f"自动检测编码失败: {str(e)}")
    encodings = ['utf-8', 'gbk', 'gb18030', 'latin-1']
    for enc in encodings:
        try:
            data = pd.read_csv(file_path, encoding=enc)
            print(f"成功使用编码: {enc}")
            break
        except:
            continue
    else:
        raise ValueError("无法解析文件，尝试了多种编码均失败")

# ==================== 数据预处理 ====================
# 清洗数据
data['日期'] = pd.to_datetime(data['日期'], errors='coerce')
data = data.dropna(subset=['日期']).sort_values('日期')

# 处理交易量
def parse_volume(volume):
    if isinstance(volume, str):
        volume = volume.upper().replace('M', 'e6').replace('K', 'e3').replace('B', 'e9')
    return float(volume)

data['交易量'] = data['交易量'].apply(parse_volume)
data = data[data['交易量'] > 0]

# ==================== 特征工程 ====================
# 计算技术指标
data['MA5'] = data['收盘'].rolling(5).mean().fillna(method='bfill')
data['MA10'] = data['收盘'].rolling(10).mean().fillna(method='bfill')

# 计算RSI
delta = data['收盘'].diff()
gain = delta.where(delta > 0, 0)
loss = -delta.where(delta < 0, 0)
avg_gain = gain.rolling(14).mean()
avg_loss = loss.rolling(14).mean()
rs = avg_gain / avg_loss
data['RSI'] = 100 - (100 / (1 + rs))
data['RSI'] = data['RSI'].fillna(50)  # 填充初始NaN值

data['Log_Volume'] = np.log(data['交易量'])

# ==================== LSTM模型 ====================
# 选择特征并标准化
features = ['收盘', '开盘', '高', '低', '交易量', 'MA5', 'MA10', 'RSI']
scaler = MinMaxScaler(feature_range=(0, 1))
scaled_data = scaler.fit_transform(data[features])

# 创建时间序列数据集
def create_dataset(dataset, look_back=30):
    X, Y = [], []
    for i in range(len(dataset)-look_back-1):
        X.append(dataset[i:(i+look_back)])
        Y.append(dataset[i+look_back, 0])
    return np.array(X), np.array(Y)

look_back = 30
X, y = create_dataset(scaled_data, look_back)

# 划分训练集
train_size = int(len(X) * 0.8)
X_train, y_train = X[:train_size], y[:train_size]

# 构建LSTM模型
model = Sequential([
    LSTM(64, return_sequences=True, input_shape=(X_train.shape[1], X_train.shape[2])),
    LSTM(32),
    Dense(1)
])
model.compile(loss='mse', optimizer='adam')

# 训练模型
print("\n训练LSTM模型...")
history = model.fit(X_train, y_train, epochs=100, batch_size=32, verbose=1)

# ==================== 预测未来29天 ====================
pred_dates = pd.date_range(start='2025-08-08', end='2025-09-05')
last_sequence = scaled_data[-look_back:]

# 逐步预测
predictions = []
for _ in range(len(pred_dates)):
    pred = model.predict(last_sequence.reshape(1, look_back, -1), verbose=0)[0,0]
    predictions.append(pred)
    # 更新序列
    new_row = np.insert(last_sequence[-1, 1:], 0, pred)
    last_sequence = np.vstack([last_sequence[1:], new_row])

# 反标准化预测结果
predictions = scaler.inverse_transform(
    np.column_stack([predictions, np.zeros((len(predictions), len(features)-1))])
)[:, 0]

# ==================== 结果可视化 ====================
plt.figure(figsize=(15, 7))

# 绘制预测点
plt.plot(pred_dates, predictions, 'o-', color='#1f77b4',
         markersize=8, linewidth=2, label='预测收盘价')

# 添加数据标签
for i, (date, pred) in enumerate(zip(pred_dates, predictions)):
    if i % 3 == 0:  # 每3天显示一个标签
        plt.text(date, pred, f'{pred:.2f}',
                 ha='center', va='bottom', fontsize=9)

plt.title('中国平安股票每日收盘价预测（2025/8/8-2025/9/5）', fontsize=15, pad=20)
plt.xlabel('日期', fontsize=12)
plt.ylabel('收盘价（元）', fontsize=12)
plt.legend(fontsize=12, loc='upper left')
plt.grid(alpha=0.3, linestyle='--')

# 调整x轴显示
plt.xticks(pred_dates[::3], rotation=45, ha='right')
plt.tight_layout()
plt.savefig('stock_prediction.png', dpi=300, bbox_inches='tight')
plt.show()

# ==================== 输出预测结果 ====================
result_df = pd.DataFrame({
    '日期': pred_dates.strftime('%Y-%m-%d'),
    '预测收盘价(元)': np.round(predictions, 2),
    '日变化(%)': np.round(np.insert(np.diff(predictions)/predictions[:-1]*100, 0, np.nan), 2)
})

print("\n未来29天每日预测结果：")
print(result_df.to_string(index=False))

# 输出统计摘要
print("\n预测统计摘要：")
print(f"• 平均预测价: {np.mean(predictions):.2f}元")
print(f"• 最高价: {np.max(predictions):.2f}元 (日期: {pred_dates[np.argmax(predictions)].strftime('%m-%d')})")
print(f"• 最低价: {np.min(predictions):.2f}元 (日期: {pred_dates[np.argmin(predictions)].strftime('%m-%d')})")
print(f"• 波动幅度: {np.ptp(predictions):.2f}元")

# 保存预测结果
result_df.to_csv('stock_predictions.csv', index=False, encoding='utf-8-sig')
print("\n预测结果已保存到 stock_predictions.csv")